package com.dtp.core.spring;

import com.dtp.common.entity.DtpExecutorProps;
import com.dtp.common.properties.DtpProperties;
import com.dtp.common.util.BeanUtil;
import com.dtp.core.reject.RejectHandlerGetter;
import com.dtp.core.support.ExecutorType;
import com.dtp.core.support.TaskQueue;
import com.dtp.core.support.wrapper.TaskWrappers;
import com.dtp.core.thread.EagerDtpExecutor;
import com.dtp.core.thread.NamedThreadFactory;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

import java.util.Map;
import java.util.concurrent.BlockingQueue;

import static com.dtp.common.constant.DynamicTpConst.ALLOW_CORE_THREAD_TIMEOUT;
import static com.dtp.common.constant.DynamicTpConst.AWAIT_TERMINATION_SECONDS;
import static com.dtp.common.constant.DynamicTpConst.NOTIFY_ENABLED;
import static com.dtp.common.constant.DynamicTpConst.NOTIFY_ITEMS;
import static com.dtp.common.constant.DynamicTpConst.PLATFORM_IDS;
import static com.dtp.common.constant.DynamicTpConst.PRE_START_ALL_CORE_THREADS;
import static com.dtp.common.constant.DynamicTpConst.QUEUE_TIMEOUT;
import static com.dtp.common.constant.DynamicTpConst.RUN_TIMEOUT;
import static com.dtp.common.constant.DynamicTpConst.TASK_WRAPPERS;
import static com.dtp.common.constant.DynamicTpConst.THREAD_POOL_ALIAS_NAME;
import static com.dtp.common.constant.DynamicTpConst.THREAD_POOL_NAME;
import static com.dtp.common.constant.DynamicTpConst.WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN;
import static com.dtp.common.em.QueueTypeEnum.buildLbq;
import static com.dtp.common.entity.NotifyItem.mergeAllNotifyItems;

/**
 * 负责动态线程池中BeanDefinition的注册
 *
 * @author yanhom
 * @since 1.0.4
 *
 * @remark muse
 **/
@Slf4j
public class DtpBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private Environment environment;

    /** 注册BeanDefinition */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        DtpProperties dtpProperties = new DtpProperties();

        // 将配置中心中的配置信息绑定到dtpProperties中
        PropertiesBinder.bindDtpProperties(environment, dtpProperties);

        // 获得线程池集合，如果不存在，则停止执行
        val executors = dtpProperties.getExecutors();
        if (CollectionUtils.isEmpty(executors)) return;

        executors.forEach(e -> {
            Class<?> executorTypeClass = ExecutorType.getClass(e.getExecutorType()); // 线程池类型

            // 构造线程池所需要的属性
            Map<String, Object> propertyValues = buildPropertyValues(e);
            Object[] args = buildConstructorArgs(executorTypeClass, e);

            // 注册bean
            BeanUtil.registerIfAbsent(registry, e.getThreadPoolName(), executorTypeClass, propertyValues, args);
        });
    }

    private Map<String, Object> buildPropertyValues(DtpExecutorProps props) {
        Map<String, Object> propertyValues = Maps.newHashMap();
        propertyValues.put(THREAD_POOL_NAME, props.getThreadPoolName()); // threadPoolName
        propertyValues.put(THREAD_POOL_ALIAS_NAME, props.getThreadPoolAliasName()); // threadPoolAliasName
        propertyValues.put(ALLOW_CORE_THREAD_TIMEOUT, props.isAllowCoreThreadTimeOut()); // allowCoreThreadTimeOut
        propertyValues.put(WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN, props.isWaitForTasksToCompleteOnShutdown()); // waitForTasksToCompleteOnShutdown
        propertyValues.put(AWAIT_TERMINATION_SECONDS, props.getAwaitTerminationSeconds()); // awaitTerminationSeconds
        propertyValues.put(PRE_START_ALL_CORE_THREADS, props.isPreStartAllCoreThreads()); // preStartAllCoreThreads
        propertyValues.put(RUN_TIMEOUT, props.getRunTimeout()); // runTimeout
        propertyValues.put(QUEUE_TIMEOUT, props.getQueueTimeout()); // queueTimeout

        val notifyItems = mergeAllNotifyItems(props.getNotifyItems());
        propertyValues.put(NOTIFY_ITEMS, notifyItems); // notifyItems
        propertyValues.put(PLATFORM_IDS, props.getPlatformIds()); // platformIds
        propertyValues.put(NOTIFY_ENABLED, props.isNotifyEnabled()); // notifyEnabled

        val taskWrappers = TaskWrappers.getInstance().getByNames(props.getTaskWrapperNames());
        propertyValues.put(TASK_WRAPPERS, taskWrappers); // taskWrappers

        return propertyValues;
    }

    /**
     * 构造创建线程池所需要的参数
     */
    private Object[] buildConstructorArgs(Class<?> clazz, DtpExecutorProps props) {
        BlockingQueue<Runnable> taskQueue; // 创建阻塞队列

        // 创建TaskQueue类型的阻塞队列，主要用于io密集型场景
        if (clazz.equals(EagerDtpExecutor.class))
            taskQueue = new TaskQueue(props.getQueueCapacity());

        // 根据queueType值，创建相应类型的阻塞队列，调用QueueTypeEnum#buildLbq(...)
        else
            taskQueue = buildLbq(props.getQueueType(), props.getQueueCapacity(), props.isFair(), props.getMaxFreeMemory());

        // 构造创建线程池所需要的参数
        return new Object[] {
                props.getCorePoolSize(),
                props.getMaximumPoolSize(),
                props.getKeepAliveTime(),
                props.getUnit(),
                taskQueue,
                new NamedThreadFactory(props.getThreadNamePrefix()),
                RejectHandlerGetter.buildRejectedHandler(props.getRejectedHandlerType())
        };
    }

    @Override
    public void setEnvironment(Environment environment) {this.environment = environment;}
}
